package com.basker.pisces.domain.entity.data;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.util.CollectionUtils;

import com.basker.pisces.core.RowContract;
import com.basker.pisces.core.query.IQuery.PagingInfo;
import com.basker.pisces.core.query.QueryInfo;
import com.basker.pisces.core.query.builder.CriterionBuilder;
import com.basker.pisces.core.query.builder.QueryBuilder;
import com.basker.pisces.core.query.meta.QueryMeta;
import com.basker.pisces.domain.entity.meta.Entity;
import com.basker.pisces.domain.property.meta.ReferenceProperty;

/**
 * 业务数据的列表搜索帮助类
 *
 * @author hangwen
 */
public class ListSearchHelper {

    public static ListSearchHelper create(Entity entity) {
        return new ListSearchHelper(entity, null);
    }

    public static ListSearchHelper create(ReferenceProperty referenceProperty) {
        return new ListSearchHelper(referenceProperty.getReferenceEntity().fullEntity(), referenceProperty);
    }

    private Entity entity;
    @SuppressWarnings("unused")
    private ReferenceProperty referenceProperty;

    private ListSearchHelper(Entity entity, ReferenceProperty referenceProperty) {
        this.entity = entity;
        this.referenceProperty = referenceProperty;
    }

    public KeywordSearchResult searchByKeywords(String[] keyWordProperties, String[] keywords) {
        KeywordSearchResult result = new KeywordSearchResult(keywords);

        boolean completed = false;

        for (String keywordProperty : keyWordProperties) {
            this.doSearch(result, keywordProperty);
            if (result.searchCompleted()) {
                completed = true;
                break;
            }
        }

        if (!completed) {
            result.markErrorKeywords();
        }

        return result;
    }

    private void doSearch(KeywordSearchResult result, String keywordProperty) {
        String pkFieldName = this.entity.getDataObjectMeta().getPkField().getName();
        QueryMeta queryMeta = this.entity.getQueryMeta();
        QueryBuilder queryBuilder = QueryBuilder.create(queryMeta).select(keywordProperty, pkFieldName);

        String[] keywords = result.getKeywordsToSearch();
        if (keywords.length == 1) {
            queryBuilder.andCriteria(CriterionBuilder.equal(keywordProperty, keywords[0]));
        } else {
            queryBuilder.andCriteria(CriterionBuilder.in(keywordProperty, keywords));
        }

        QueryInfo queryInfo = queryBuilder.buildQueryInfo();

        IRowListDataEntity rowListDataEntity = this.entity.createRowListDataEntity();
        List<RowContract> rows = rowListDataEntity.query(queryInfo, PagingInfo.NO_PAGING);

        // 用keyWord和id构建一个map
        Map<String, Object> keyWordIdMap = rows.stream().collect(Collectors
                .toMap(row -> row.get(keywordProperty).toString(), row -> row.get(pkFieldName), (oldV, newV) -> oldV));
        result.addResult(keyWordIdMap);
    }

    public static class KeywordSearchResult {

        private Set<String> keywordsToSearch = new HashSet<>();
        private Map<String, Object> keywordsResult = null;
        private Set<String> errorKeywords = null;

        KeywordSearchResult(String[] keyWords) {
            for (String keyWord : keyWords) {
                keywordsToSearch.add(keyWord);
            }
        }

        public Object getIdValue(String keyword) {
            return keywordsResult != null ? keywordsResult.get(keyword) : null;
        }

        void addResult(Map<String, Object> result) {
            if (keywordsResult == null) {
                keywordsResult = new HashMap<>();
            }

            keywordsResult.putAll(result);
            keywordsToSearch.removeAll(result.keySet());
        }

        List<String> getErrorKeywords() {
            if (errorKeywords == null) {
                return null;
            }

            return errorKeywords.stream().collect(Collectors.toList());
        }

        String[] getKeywordsToSearch() {
            return keywordsToSearch.toArray(new String[keywordsToSearch.size()]);
        }

        void markErrorKeywords() {
            if (errorKeywords == null) {
                errorKeywords = new HashSet<>();
            }

            errorKeywords.addAll(keywordsToSearch);
            keywordsToSearch.clear();
        }

        boolean searchCompleted() {
            return CollectionUtils.isEmpty(keywordsToSearch);
        }

    }

}
